/*
 * Copyright (c) 2024 Shenzhen Kaihong Digital Industry Development Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "securec.h"
#include "sle_discover_announce_parcel.h"
#include "sle_hilog.h"

namespace OHOS {
namespace NearLink {
namespace SleStandard {
AnnounceParam::AnnounceParam(const SleAnnounceParam &param)
{
    handle_ = param.handle;
    mode_ = param.mode;
    role_ = param.role;
    level_ = param.level;
    anneIntervalMin_ = param.annonceIntervalMin;
    anneIntervalMax_ = param.annonceIntervalMax;
    anneChannelMap_ = param.channelMap;
    connIntervalMin_ = param.connectIntervalMin;
    connIntervalMax_ = param.connectIntervalMax;
    connLatency_ = param.connectLatency;
    connTimeout_ = param.connectTimeout;
}

bool AnnounceParam::Marshalling(Parcel &parcel) const
{
    if (!parcel.WriteUint8(handle_)) {
        return false;
    }
    if (!parcel.WriteUint8(mode_)) {
        return false;
    }
    if (!parcel.WriteUint8(role_)) {
        return false;
    }
    if (!parcel.WriteUint8(level_)) {
        return false;
    }
    if (!parcel.WriteUint32(anneIntervalMin_)) {
        return false;
    }
    if (!parcel.WriteUint32(anneIntervalMax_)) {
        return false;
    }
    if (!parcel.WriteUint8(anneChannelMap_)) {
        return false;
    }
    if (!parcel.WriteUint16(connIntervalMin_)) {
        return false;
    }
    if (!parcel.WriteUint16(connIntervalMax_)) {
        return false;
    }
    if (!parcel.WriteUint16(connLatency_)) {
        return false;
    }
    if (!parcel.WriteUint16(connTimeout_)) {
        return false;
    }
    return true;
}

AnnounceParam *AnnounceParam::Unmarshalling(Parcel &parcel)
{
    AnnounceParam *param = new AnnounceParam();
    if (param != nullptr && !param->ReadFromParcel(parcel)) {
        delete param;
        param = nullptr;
    }
    return param;
}

bool AnnounceParam::ReadFromParcel(Parcel &parcel)
{
    if (!parcel.ReadUint8(handle_)) {
        return false;
    }
    if (!parcel.ReadUint8(mode_)) {
        return false;
    }
    if (!parcel.ReadUint8(role_)) {
        return false;
    }
    if (!parcel.ReadUint8(level_)) {
        return false;
    }
    if (!parcel.ReadUint32(anneIntervalMin_)) {
        return false;
    }
    if (!parcel.ReadUint32(anneIntervalMax_)) {
        return false;
    }
    if (!parcel.ReadUint8(anneChannelMap_)) {
        return false;
    }
    if (!parcel.ReadUint16(connIntervalMin_)) {
        return false;
    }
    if (!parcel.ReadUint16(connIntervalMax_)) {
        return false;
    }
    if (!parcel.ReadUint16(connLatency_)) {
        return false;
    }
    if (!parcel.ReadUint16(connTimeout_)) {
        return false;
    }
    return true;
}

void AnnounceParam::ConvertToSleAnnounceParam(SleAnnounceParam &param) const
{
    param.handle = handle_;
    param.mode = (SleAnnounceMode)mode_;
    param.role = (SleAnnounceRole)role_;
    param.level = (SleAnnounceLevel)level_;
    param.annonceIntervalMin = anneIntervalMin_;
    param.annonceIntervalMax = anneIntervalMax_;
    param.channelMap = (SleAnnounceChanel)anneChannelMap_;
    param.connectIntervalMin = connIntervalMin_;
    param.connectIntervalMax = connIntervalMax_;
    param.connectLatency = connLatency_;
    param.connectTimeout = connTimeout_;
}

SleErrorCode AnnounceParam::CheckAnnounceParam(const SleAnnounceParam &param)
{
    SLE_ASSERT_AND_RETURN_RET_LOG(
        (param.mode >= SLE_ANNOUNCE_NONCONN_NONSCAN_MODE && param.mode <= SLE_ANNOUNCE_CONNECTABLE_SCANABLE_MODE) ||
        param.mode == SLE_ANNOUNCE_CONNECTABLE_DIRECTED_MODE, SLE_ERR_INVALID_PARAM, "param announce mode error!");
    SLE_ASSERT_AND_RETURN_RET_LOG(
        param.role >= SLE_ANNOUNCE_T_ROAL_CAN_NEGO && param.role <= SLE_ANNOUNCE_G_ROAL_NO_NEGO,
        SLE_ERR_INVALID_PARAM, "param announce role error!");
    SLE_ASSERT_AND_RETURN_RET_LOG(param.level >= SLE_ANNOUNCE_NONE_LEVEL && param.level <= SLE_ANNOUNCE_SPECIAL_LEVEL,
        SLE_ERR_INVALID_PARAM, "param announce level error!");
    SLE_ASSERT_AND_RETURN_RET_LOG(param.annonceIntervalMin >= 0x000020 && param.annonceIntervalMin <= 0xFFFFFF,
        SLE_ERR_INVALID_PARAM, "param announce interval min error!");
    SLE_ASSERT_AND_RETURN_RET_LOG(param.annonceIntervalMax >= 0x000020 && param.annonceIntervalMax <= 0xFFFFFF,
        SLE_ERR_INVALID_PARAM, "param announce interval max error!");
    SLE_ASSERT_AND_RETURN_RET_LOG(param.annonceIntervalMin <= param.annonceIntervalMax,
        SLE_ERR_INVALID_PARAM, "param announce interval error!");
    SLE_ASSERT_AND_RETURN_RET_LOG(
        param.channelMap == SLE_ANNOUNCE_76_CHANEL || param.channelMap == SLE_ANNOUNCE_77_CHANEL ||
        param.channelMap == SLE_ANNOUNCE_78_CHANEL || param.channelMap == SLE_ANNOUNCE_DEFAULT_ALL_CHANEL,
        SLE_ERR_INVALID_PARAM,"param announce interval max error!");
    if (param.role != SLE_ANNOUNCE_T_ROAL_NO_NEGO) {
        SLE_ASSERT_AND_RETURN_RET_LOG(param.connectIntervalMin >= 0x000A && param.connectIntervalMin <= 0x3E80,
            SLE_ERR_INVALID_PARAM, "param announce connect interval min error!");
        SLE_ASSERT_AND_RETURN_RET_LOG(param.connectIntervalMax >= 0x000A && param.connectIntervalMax <= 0x3E80,
            SLE_ERR_INVALID_PARAM, "param announce connect interval max error!");
        SLE_ASSERT_AND_RETURN_RET_LOG(param.connectIntervalMin <= param.connectIntervalMax,
            SLE_ERR_INVALID_PARAM, "param announce connect interval error!");
        SLE_ASSERT_AND_RETURN_RET_LOG(param.connectLatency <= 0x01F3,
            SLE_ERR_INVALID_PARAM, "param announce connect latency error!");
        SLE_ASSERT_AND_RETURN_RET_LOG(param.connectTimeout <= 0x0C80,
            SLE_ERR_INVALID_PARAM, "param announce connect timeout error!");
        SLE_ASSERT_AND_RETURN_RET_LOG(param.connectLatency < param.connectTimeout,
            SLE_ERR_INVALID_PARAM, "param announce connect latency than timeout error!");
    }
    return SLE_NO_ERROR;
}

AnnounceData::AnnounceData(const SleAnnounceData &data)
{
    length_ = data.announceLength;
    if (data.announceData != nullptr && length_ != 0) {
        data_ = std::make_unique<uint8_t[]>(length_);
        (void)memcpy_s(data_.get(), length_, data.announceData, data.announceLength);
    } else {
        data_ = nullptr;
        length_ = 0;
    }

    rspLength_ = data.responceLength;
    if (data.responceData != nullptr && rspLength_ != 0) {
        rspData_ = std::make_unique<uint8_t[]>(rspLength_);
        (void)memcpy_s(rspData_.get(), rspLength_, data.responceData, data.responceLength);
    } else {
        rspData_ = nullptr;
        rspLength_ = 0;
    }
}

bool AnnounceData::Marshalling(Parcel &parcel) const
{
    if (!parcel.WriteUint16(length_)) {
        return false;
    }
    for (size_t i = 0; i < length_; i++) {
        if(!parcel.WriteUint8(data_[i])) {
            return false;
        }
    }
    if (!parcel.WriteUint16(rspLength_)) {
        return false;
    }
    for (size_t i = 0; i < rspLength_; i++) {
        if(!parcel.WriteUint8(rspData_[i])) {
            return false;
        }
    }
    return true;
}

AnnounceData *AnnounceData::Unmarshalling(Parcel &parcel)
{
    AnnounceData *data = new AnnounceData();
    if (data != nullptr && !data->ReadFromParcel(parcel)) {
        delete data;
        data = nullptr;
    }
    return data;
}

bool AnnounceData::ReadFromParcel(Parcel &parcel)
{
    if (!parcel.ReadUint16(length_)) {
        return false;
    }
    if (length_ != 0) {
        uint8_t data[length_];
        for (size_t i = 0; i < length_; i++) {
            if (!parcel.ReadUint8(data[i])) {
                return false;
            }
        }
        data_ = std::make_unique<uint8_t[]>(length_);
        if (memcpy_s(data_.get(), length_, data, length_) != SLE_NO_ERROR) {
            return false;
        }
    }
    if (!parcel.ReadUint16(rspLength_)) {
        return false;
    }
    if (rspLength_ != 0) {
        uint8_t rspData[rspLength_];
        for (size_t i = 0; i < rspLength_; i++) {
            if (!parcel.ReadUint8(rspData[i])) {
                return false;
            }
        }
        rspData_ = std::make_unique<uint8_t[]>(rspLength_);
        if (memcpy_s(rspData_.get(), rspLength_, rspData, rspLength_) != SLE_NO_ERROR) {
            return false;
        }
    }
    return true;
}

void AnnounceData::ConvertToSleAnnounceData(SleAnnounceData &data) const
{
    data.announceLength = length_;
    data.announceData = data_.get();
    data.responceLength = rspLength_;
    data.responceData = rspData_.get();
}

SleErrorCode AnnounceData::CheckAnnounceData(const SleAnnounceData &data)
{
    SLE_ASSERT_AND_RETURN_RET_LOG(data.announceData && data.responceData,
        SLE_ERR_INVALID_PARAM, "param announce data or rspdata ptr not init error!");
    SLE_ASSERT_AND_RETURN_RET_LOG(data.announceLength <= SLE_ANNOUNCE_DATA_ANN_MAX_LENGTH,
        SLE_ERR_INVALID_PARAM, "param announce data length error!");
    SLE_ASSERT_AND_RETURN_RET_LOG(data.responceLength <= SLE_ANNOUNCE_DATA_MAX_RSP_LENGTH,
        SLE_ERR_INVALID_PARAM, "param announce rsp data length error!");
    return SLE_NO_ERROR;
}
} // SleStandard
} // NearLink
} // OHOS